package com.sheliduan.itlearning.common.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sheliduan.itlearning.common.aspect.ApiOperationLog;
import com.sheliduan.itlearning.common.aspect.AuthAccess;
import com.sheliduan.itlearning.common.domain.dos.*;
import com.sheliduan.itlearning.common.domain.mapper.*;
import com.sheliduan.itlearning.common.markdown.provider.MarkdownHelper;
import com.sheliduan.itlearning.common.model.vos.*;
import com.sheliduan.itlearning.common.utils.PageResponseData;
import com.sheliduan.itlearning.common.utils.ResponseData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 断舍离
 * @date: 2025/4/14 17:03
 * @description:
 **/
@RestController
@RequestMapping("/index")
public class IndexController {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInterestMapper userInterestMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private ArticleCourseMapper articleCourseMapper;

    @Autowired
    private ArticleTagRelMapper articleTagRelMapper;

    @Autowired
    private VideoCourseMapper videoCourseMapper;

    @Autowired
    private VideoTagRelMapper videoTagRelMapper;

    @Autowired
    private UserBoughtCourseMapper userBoughtCourseMapper;

    @PostMapping("/course/search")
    @ApiOperationLog(description = "获取模糊分页搜索课程")
    @AuthAccess
    public PageResponseData search(@RequestBody @Validated SearchCoursePageListReqVO reqVO) {
        long current = reqVO.getCurrent();
        long size = reqVO.getSize();
        String title = reqVO.getTitle();

        // 1. 搜索图文课程
        LambdaQueryWrapper<ArticleCourseDO> articleWrapper = Wrappers.lambdaQuery();
        articleWrapper.like(ArticleCourseDO::getTitle, title)
                .and(w -> w.eq(ArticleCourseDO::getStatus, 2).or().eq(ArticleCourseDO::getStatus, 4));
        List<ArticleCourseDO> articleCourses = articleCourseMapper.selectList(articleWrapper);

        // 2. 搜索视频课程
        LambdaQueryWrapper<VideoCourseDO> videoWrapper = Wrappers.lambdaQuery();
        videoWrapper.like(VideoCourseDO::getTitle, title)
                .and(w -> w.eq(VideoCourseDO::getStatus, 2).or().eq(VideoCourseDO::getStatus, 4));
        List<VideoCourseDO> videoCourses = videoCourseMapper.selectList(videoWrapper);

        // 3. 转换为响应VO
        List<SearchCoursePageListRspVO> allCourses = new ArrayList<>();
        
        // 添加图文课程
        allCourses.addAll(articleCourses.stream()
                .map(article -> SearchCoursePageListRspVO.builder()
                        .id(article.getId())
                        .type(0)
                        .cover(article.getCover())
                        .title(article.getTitle())
                        .createTime(article.getCreateTime())
                        .build())
                .collect(Collectors.toList()));
        
        // 添加视频课程
        allCourses.addAll(videoCourses.stream()
                .map(video -> SearchCoursePageListRspVO.builder()
                        .id(video.getId())
                        .type(1)
                        .cover(video.getCover())
                        .title(video.getTitle())
                        .createTime(video.getCreateTime())
                        .build())
                .collect(Collectors.toList()));

        // 4. 按创建时间倒序排序
        allCourses.sort((a, b) -> b.getCreateTime().compareTo(a.getCreateTime()));

        // 5. 手动分页
        int total = allCourses.size();
        int fromIndex = (int) ((current - 1) * size);
        int toIndex = Math.min((int) (current * size), total);

        List<SearchCoursePageListRspVO> pageData = fromIndex < toIndex 
                ? allCourses.subList(fromIndex, toIndex) 
                : new ArrayList<>();
        Page<SearchCoursePageListRspVO> page = new Page<>(current, size, total);
        page.setRecords(pageData);
        return PageResponseData.success(page, pageData);
    }

    @PostMapping("/course/listByRecommend")
    @ApiOperationLog(description = "获取管理员推荐轮播课程")
    @AuthAccess
    public ResponseData listByInterest() {
        LambdaQueryWrapper<ArticleCourseDO> wrapperArticle = Wrappers.lambdaQuery();
        wrapperArticle.eq(ArticleCourseDO::getStatus, "4");
        List<ArticleCourseDO> articleCourseDOS = articleCourseMapper.selectList(wrapperArticle);
        List<FindCourseListRspVO> vos = new ArrayList<>();
        List<FindCourseListRspVO> articleVos = new ArrayList<>();
        articleVos = articleCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                .map(articleCourseDO -> FindCourseListRspVO.builder()
                        .id(articleCourseDO.getId())
                        .title(articleCourseDO.getTitle())
                        .cover(articleCourseDO.getCover())
                        .summary(articleCourseDO.getSummary())
                        .price(articleCourseDO.getPrice())
                        .username(userMapper.selectById(articleCourseDO.getUserId()).getUsername())
                        .type(articleCourseDO.getType())
                        .status(articleCourseDO.getStatus())
                        .watchNums(articleCourseDO.getWatchNums())
                        .createTime(articleCourseDO.getCreateTime())
                        .build())
                .collect(Collectors.toList());
        vos.addAll(articleVos);
        LambdaQueryWrapper<VideoCourseDO> wrapperVideo = Wrappers.lambdaQuery();
        wrapperVideo.eq(VideoCourseDO::getStatus, "4");
        List<VideoCourseDO> videoCourseDOS = videoCourseMapper.selectList(wrapperVideo);
        List<FindCourseListRspVO> videoVos = new ArrayList<>();
        videoVos = videoCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                .map(videoCourseDO -> FindCourseListRspVO.builder()
                        .id(videoCourseDO.getId())
                        .title(videoCourseDO.getTitle())
                        .cover(videoCourseDO.getCover())
                        .summary(videoCourseDO.getSummary())
                        .price(videoCourseDO.getPrice())
                        .username(userMapper.selectById(videoCourseDO.getUserId()).getUsername())
                        .type(videoCourseDO.getType())
                        .status(videoCourseDO.getStatus())
                        .watchNums(videoCourseDO.getWatchNums())
                        .createTime(videoCourseDO.getCreateTime())
                        .build())
                .collect(Collectors.toList());
        vos.addAll(videoVos);
        return ResponseData.success(vos);
    }

    @PostMapping("/course/listByInterest")
    @ApiOperationLog(description = "获取用户所感兴趣标签下的课程")
    @AuthAccess
    public ResponseData listByInterest(@RequestBody @Validated UserInterestReqVO reqVO) {
        List<Integer> tagIds = reqVO.getTagIds();
        List<FindCourseListRspVO> vos = new ArrayList<>();
        for (Integer tagId : tagIds) {
            vos.addAll(getCoursesByTagId(tagId));
        }
        // 若用户没有选择过感兴趣标签, 封装全部课程数据
        if(vos.isEmpty()) {
            List<ArticleCourseDO> articleCourseDOS = articleCourseMapper.selectList(null);
            List<VideoCourseDO> videoCourseDOS = videoCourseMapper.selectList(null);
            List<FindCourseListRspVO> articleVos = articleCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                    .map(articleCourseDO -> FindCourseListRspVO.builder()
                            .id(articleCourseDO.getId())
                            .title(articleCourseDO.getTitle())
                            .cover(articleCourseDO.getCover())
                            .summary(articleCourseDO.getSummary())
                            .price(articleCourseDO.getPrice())
                            .username(userMapper.selectById(articleCourseDO.getUserId()).getUsername())
                            .type(articleCourseDO.getType())
                            .status(articleCourseDO.getStatus())
                            .watchNums(articleCourseDO.getWatchNums())
                            .createTime(articleCourseDO.getCreateTime())
                            .build())
                    .collect(Collectors.toList());
            vos.addAll(articleVos);
            List<FindCourseListRspVO> videoVos = videoCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                    .map(videoCourseDO -> FindCourseListRspVO.builder()
                            .id(videoCourseDO.getId())
                            .title(videoCourseDO.getTitle())
                            .cover(videoCourseDO.getCover())
                            .summary(videoCourseDO.getSummary())
                            .price(videoCourseDO.getPrice())
                            .username(userMapper.selectById(videoCourseDO.getUserId()).getUsername())
                            .type(videoCourseDO.getType())
                            .status(videoCourseDO.getStatus())
                            .watchNums(videoCourseDO.getWatchNums())
                            .createTime(videoCourseDO.getCreateTime())
                            .build())
                    .collect(Collectors.toList());
            vos.addAll(videoVos);
        }
        vos = vos.stream().sorted(Comparator.comparing(FindCourseListRspVO::getWatchNums).reversed()).collect(Collectors.toList());
        return ResponseData.success(vos);
    }
    @PostMapping("/course/listAllArticleCourses")
    @ApiOperationLog(description = "获取所有图文课程")
    @AuthAccess
    public ResponseData listAllArticleCourses() {
        List<ArticleCourseDO> articleCourseDOS = articleCourseMapper.selectList(null);
        List<FindCourseListRspVO> articleVos = articleCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                .map(articleCourseDO -> FindCourseListRspVO.builder()
                        .id(articleCourseDO.getId())
                        .title(articleCourseDO.getTitle())
                        .cover(articleCourseDO.getCover())
                        .summary(articleCourseDO.getSummary())
                        .price(articleCourseDO.getPrice())
                        .username(userMapper.selectById(articleCourseDO.getUserId()).getUsername())
                        .type(articleCourseDO.getType())
                        .status(articleCourseDO.getStatus())
                        .watchNums(articleCourseDO.getWatchNums())
                        .createTime(articleCourseDO.getCreateTime())
                        .build())
                .collect(Collectors.toList());

        articleVos = articleVos.stream().sorted(Comparator.comparing(FindCourseListRspVO::getWatchNums).reversed()).collect(Collectors.toList());
        return ResponseData.success(articleVos);
    }

    @PostMapping("/course/listAllVideoCourses")
    @ApiOperationLog(description = "获取所有视频课程")
    @AuthAccess
    public ResponseData listAllVideoCourses() {
        List<VideoCourseDO> videoCourseDOS = videoCourseMapper.selectList(null);
        List<FindCourseListRspVO> videoVos = videoCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                .map(videoCourseDO -> FindCourseListRspVO.builder()
                        .id(videoCourseDO.getId())
                        .title(videoCourseDO.getTitle())
                        .cover(videoCourseDO.getCover())
                        .summary(videoCourseDO.getSummary())
                        .price(videoCourseDO.getPrice())
                        .username(userMapper.selectById(videoCourseDO.getUserId()).getUsername())
                        .type(videoCourseDO.getType())
                        .status(videoCourseDO.getStatus())
                        .watchNums(videoCourseDO.getWatchNums())
                        .createTime(videoCourseDO.getCreateTime())
                        .build())
                .collect(Collectors.toList());

        videoVos = videoVos.stream().sorted(Comparator.comparing(FindCourseListRspVO::getWatchNums).reversed()).collect(Collectors.toList());
        return ResponseData.success(videoVos);
    }


    @PostMapping("/user/addInterestTags")
    @ApiOperationLog(description = "选择感兴趣的标签")
    @AuthAccess
    public ResponseData addInterestTags(@RequestBody @Validated SelectInterestTagReqVO reqVO) {
        // 用户新选择的标签
        Set<Integer> newTagIds = reqVO.getTagIds();
        LambdaQueryWrapper<UserInterestDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserInterestDO::getUserId, reqVO.getUserId());
        // 用户之前选择的标签id Set集合
        Set<Integer> oldTagIds = userInterestMapper.selectList(wrapper).stream().map(UserInterestDO::getTagId).collect(Collectors.toSet());
        // 用户之前选择的标签集合
        List<UserInterestDO> oldTags = userInterestMapper.selectList(wrapper);
        // 说明没有改变，直接返回即可
        if(newTagIds.equals(oldTagIds)) {
            return ResponseData.success();
        }else {
            for (UserInterestDO oldTag : oldTags) {
                // 说明新选择标签中没有之前选择的标签, 需要将之前选择的标签删除
                if(!newTagIds.contains(oldTag.getTagId())) {
                    userInterestMapper.deleteById(oldTag.getId());
                // 说明新选择的标签中包含之前选择的标签, 不需要重复添加
                } else {
                    newTagIds.remove(oldTag.getTagId());
                }
            }
            // 剩下的newTagIds就是真正新增的
            for (Integer newTagId : newTagIds) {
                UserInterestDO userInterestDO = new UserInterestDO();
                userInterestDO.setUserId(reqVO.getUserId());
                userInterestDO.setTagId(newTagId);
                userInterestMapper.insert(userInterestDO);
            }
        }
        return ResponseData.success();

    }

    @PostMapping("/user/findUserInterestTags")
    @ApiOperationLog(description = "获取该用户感兴趣的标签")
    @AuthAccess
    public ResponseData findUserInterestTags(@RequestBody @Validated IdReqVO reqVO) {
        Integer userId = reqVO.getId();
        LambdaQueryWrapper<UserInterestDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserInterestDO::getUserId, userId);
        List<TagDO> tags = userInterestMapper.selectList(wrapper).stream().map(e -> {
            TagDO tagDO = tagMapper.selectById(e.getTagId());
            return tagDO;
        }).collect(Collectors.toList());
        return ResponseData.success(tags);
    }

    @PostMapping("/course/listByTagId")
    @ApiOperationLog(description = "根据标签获取课程列表")
    @AuthAccess
    public ResponseData listByTagId(@RequestBody @Validated IdReqVO reqVO) {
        return ResponseData.success(getCoursesByTagId(reqVO.getId()));
    }

    @PostMapping("/course/findArticleDetail")
    @ApiOperationLog(description = "获取文章课程详情")
    @AuthAccess
    public ResponseData findArticleDetail(@RequestBody @Validated FindCourseDetailReqVO reqVO) {
        ArticleCourseDO articleCourseDO = articleCourseMapper.selectById(reqVO.getCourseId());
        LambdaQueryWrapper<ArticleTagRelDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ArticleTagRelDO::getArticleId, reqVO.getCourseId());
        Integer tagId = articleTagRelMapper.selectOne(wrapper).getTagId();
        FindArticleDetailRspVO vo = FindArticleDetailRspVO.builder()
                .id(articleCourseDO.getId())
                .title(articleCourseDO.getTitle())
                .content(MarkdownHelper.convertMarkdown2Html(articleCourseDO.getContent()))
                .username(userMapper.selectById(articleCourseDO.getUserId()).getUsername())
                .price(articleCourseDO.getPrice())
                .watchNums(articleCourseDO.getWatchNums())
                .tagName(tagMapper.selectById(tagId).getName())
                .createTime(articleCourseDO.getCreateTime()).build();
        articleCourseDO.setWatchNums(articleCourseDO.getWatchNums()+1);
        articleCourseMapper.updateById(articleCourseDO);
        LambdaQueryWrapper<UserBoughtCourseDO> wrapperTwo = Wrappers.lambdaQuery();
        wrapperTwo.eq(UserBoughtCourseDO::getUserId, reqVO.getUserId());
        wrapperTwo.eq(UserBoughtCourseDO::getType, reqVO.getType());
        wrapperTwo.eq(UserBoughtCourseDO::getCourseId, reqVO.getCourseId());
        UserBoughtCourseDO userBoughtCourseDO = userBoughtCourseMapper.selectOne(wrapperTwo);
        // 判断返回的详情是否允许查看
        if(userBoughtCourseDO != null || vo.getPrice() == 0) {
            vo.setIsShow(1);
        }else {
            vo.setIsShow(0);
            // 不能返回文章主题内容
            vo.setContent(null);
        }
        return ResponseData.success(vo);
    }

    @PostMapping("/course/findVideoDetail")
    @ApiOperationLog(description = "获取视频课程详情")
    @AuthAccess
    public ResponseData findVideoDetail(@RequestBody @Validated FindCourseDetailReqVO reqVO) {
        VideoCourseDO videoCourseDO = videoCourseMapper.selectById(reqVO.getCourseId());
        LambdaQueryWrapper<VideoTagRelDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(VideoTagRelDO::getVideoId, reqVO.getCourseId());
        Integer tagId = videoTagRelMapper.selectOne(wrapper).getTagId();
        FindVideoDetailRspVO vo = FindVideoDetailRspVO.builder()
                .id(videoCourseDO.getId())
                .title(videoCourseDO.getTitle())
                .cover(videoCourseDO.getCover())
                .avatar(userMapper.selectById(videoCourseDO.getUserId()).getAvatar())
                .location(videoCourseDO.getLocation())
                .username(userMapper.selectById(videoCourseDO.getUserId()).getUsername())
                .price(videoCourseDO.getPrice())
                .watchNums(videoCourseDO.getWatchNums())
                .tagName(tagMapper.selectById(tagId).getName())
                .createTime(videoCourseDO.getCreateTime()).build();
        // 更新浏览量
        videoCourseDO.setWatchNums(videoCourseDO.getWatchNums()+1);
        videoCourseMapper.updateById(videoCourseDO);
        LambdaQueryWrapper<UserBoughtCourseDO> wrapperTwo = Wrappers.lambdaQuery();
        wrapperTwo.eq(UserBoughtCourseDO::getUserId, reqVO.getUserId());
        wrapperTwo.eq(UserBoughtCourseDO::getType, reqVO.getType());
        wrapperTwo.eq(UserBoughtCourseDO::getCourseId, reqVO.getCourseId());
        UserBoughtCourseDO userBoughtCourseDO = userBoughtCourseMapper.selectOne(wrapperTwo);
        // 判断返回的详情是否允许查看
        if(userBoughtCourseDO != null || vo.getPrice() == 0) {
            vo.setIsShow(1);
        }else {
            vo.setIsShow(0);
            // 不能返回视频链接
            vo.setLocation(null);
        }
        return ResponseData.success(vo);
    }

    private List<FindCourseListRspVO> getCoursesByTagId(Integer tagId) {
        List<FindCourseListRspVO> vos = new ArrayList<>();
        LambdaQueryWrapper<ArticleTagRelDO> wrapperArticle = Wrappers.lambdaQuery();
        wrapperArticle.eq(ArticleTagRelDO::getTagId, tagId);
        // 该标签下的所有文章课程
        List<Integer> articleIds = articleTagRelMapper.selectList(wrapperArticle)
                .stream().map(ArticleTagRelDO::getArticleId).collect(Collectors.toList());
        List<FindCourseListRspVO> articleVos = null;
        // 若查询分页数据不为空, 则采用流操作封装vo集合
        if(!CollectionUtils.isEmpty(articleIds)){
            List<ArticleCourseDO> articleCourseDOS = articleCourseMapper.selectBatchIds(articleIds);
            // 只展示审核通过和推荐课程
            articleVos = articleCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                    .map(articleCourseDO -> FindCourseListRspVO.builder()
                            .id(articleCourseDO.getId())
                            .title(articleCourseDO.getTitle())
                            .cover(articleCourseDO.getCover())
                            .summary(articleCourseDO.getSummary())
                            .price(articleCourseDO.getPrice())
                            .username(userMapper.selectById(articleCourseDO.getUserId()).getUsername())
                            .type(articleCourseDO.getType())
                            .status(articleCourseDO.getStatus())
                            .watchNums(articleCourseDO.getWatchNums())
                            .createTime(articleCourseDO.getCreateTime())
                            .build())
                    .collect(Collectors.toList());
            vos.addAll(articleVos);
        }
        LambdaQueryWrapper<VideoTagRelDO> wrapperVideo = Wrappers.lambdaQuery();
        wrapperVideo.eq(VideoTagRelDO::getTagId, tagId);
        // 该标签下的所有文章课程
        List<Integer> videoIds = videoTagRelMapper.selectList(wrapperVideo)
                .stream().map(VideoTagRelDO::getVideoId).collect(Collectors.toList());
        List<FindCourseListRspVO> videoVos = null;
        // 若查询分页数据不为空, 则采用流操作封装vo集合
        if(!CollectionUtils.isEmpty(videoIds)){
            List<VideoCourseDO> videoCourseDOS = videoCourseMapper.selectBatchIds(videoIds);
            videoVos = videoCourseDOS.stream().filter(e -> e.getStatus()==2||e.getStatus()==4)
                    .map(videoCourseDO -> FindCourseListRspVO.builder()
                            .id(videoCourseDO.getId())
                            .title(videoCourseDO.getTitle())
                            .cover(videoCourseDO.getCover())
                            .summary(videoCourseDO.getSummary())
                            .price(videoCourseDO.getPrice())
                            .username(userMapper.selectById(videoCourseDO.getUserId()).getUsername())
                            .type(videoCourseDO.getType())
                            .status(videoCourseDO.getStatus())
                            .watchNums(videoCourseDO.getWatchNums())
                            .createTime(videoCourseDO.getCreateTime())
                            .build())
                    .collect(Collectors.toList());
            vos.addAll(videoVos);
        }
        // 按浏览量倒序排序
        return vos.stream().sorted(Comparator.comparing(FindCourseListRspVO::getWatchNums).reversed()).collect(Collectors.toList());
    }
}
